/*   
 * Copyright (C) 2015 O. Wu
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.osx.my2048.view;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;

import org.osx.my2048.util.Util;

/**
 * @author O. Wu
 * @date 15/02/18
 */
public class GameBoardListener implements KeyListener {
	
	/** The instance of Gameboard. */
	private GameBoard instance;

	public GameBoardListener(GameBoard instance) {
		this.instance = instance;
	}

	/**
	 * Handle the key event.
	 */
	@Override
	public void keyPressed(KeyEvent e) {
		int[] moveBefore = Block.valueArray(instance.getBlock());
		int[] moveAfter = null;
		int[] tmpArray = Arrays.copyOf(moveBefore, moveBefore.length);
		
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			moveAfter = allMoveUp(moveBefore);
			break;
		case KeyEvent.VK_DOWN:
			moveAfter = allMoveDown(moveBefore);
			break;
		case KeyEvent.VK_LEFT:
			moveAfter = allMoveLeft(moveBefore);
			break;
		case KeyEvent.VK_RIGHT:
			moveAfter = allMoveRight(moveBefore);
			break;
		default:
			return;
		}
		
		// validate and modified the state of the game.
		instance.checkGameState(moveAfter);

		switch (instance.state()) {
		case WIN:
			instance.activateGameEvent("YOU WIN!");
			break;
		case LOSE:
			instance.activateGameEvent("GAME OVER!");
			break;
		// instance.state() == State.MOVEABLE is true
		default:
			if (!Util.arrayEquals(tmpArray, moveAfter)) {
				instance.showMoveableBlock(1);
			}
			break;
		}
	}

	@Override
	public void keyReleased(KeyEvent e) {
	}

	@Override
	public void keyTyped(KeyEvent e) {
	}

	/**
	 * Move up and update the value.
	 */
	private int[] allMoveUp(int[] oldArray) {
		int base = GameBoard.BLOCK_PER_LINE;

		for (int offset = 0; offset < base; offset++) {
			Integer[] tmpArray = new Integer[base];
			for (int i = 0; i < tmpArray.length; i++) {
				tmpArray[i] = oldArray[i * base + offset];
			}

			tmpArray = Util.allMerge(Arrays.asList(tmpArray));
			for (int i = 0; i < tmpArray.length; i++) {
				oldArray[i * base + offset] = tmpArray[i];
			}
		}

		return oldArray;
	}
	
	/**
	 * Move down and update the value.
	 */
	private int[] allMoveDown(int[] oldArray) {
		int base = GameBoard.BLOCK_PER_LINE;

		for (int offset = 0; offset < base; offset++) {
			Integer[] tmpArray = new Integer[base];
			for (int i = tmpArray.length - 1; i >= 0; i--) {
				tmpArray[tmpArray.length - i - 1] = oldArray[i * base + offset];
			}

			tmpArray = Util.allMerge(Arrays.asList(tmpArray));
			for (int i = tmpArray.length - 1; i >= 0; i--) {
				oldArray[i * base + offset] = tmpArray[tmpArray.length - i - 1];
			}
		}

		return oldArray;
	}

	/**
	 * Move left and update the value.
	 */
	private int[] allMoveLeft(int[] oldArray) {
		int base = GameBoard.BLOCK_PER_LINE;

		for (int i = 0; i < oldArray.length; i += base) {
			Integer[] tmpArray = new Integer[base];
			for (int offset = 0; offset < tmpArray.length; offset++) {
				tmpArray[offset] = oldArray[i + offset];
			}

			tmpArray = Util.allMerge(Arrays.asList(tmpArray));
			for (int offset = 0; offset < tmpArray.length; offset++) {
				oldArray[i + offset] = tmpArray[offset];
			}
		}

		return oldArray;
	}

	/**
	 * Move right and update the value.
	 */
	private int[] allMoveRight(int[] oldArray) {
		int base = GameBoard.BLOCK_PER_LINE;

		for (int i = base; i < oldArray.length + base; i += base) {
			Integer[] tmpArray = new Integer[base];
			for (int offset = 0; offset < tmpArray.length; offset++) {
				tmpArray[offset] = oldArray[i - offset - 1];
			}

			tmpArray = Util.allMerge(Arrays.asList(tmpArray));
			for (int offset = 0; offset < tmpArray.length; offset++) {
				oldArray[i - offset - 1] = tmpArray[offset];
			}
		}

		return oldArray;
	}
}
